BITS 32

section .data
align 8
global idt
idt:
    ; 256 entries * 8 bytes
    times 256 dq 0

global idtr
idtr:
    dw (8*256 - 1)
    dd idt

CODE_SEL     equ 0x08
PIC1_CMD     equ 0x20
PIC1_DATA    equ 0x21
PIC2_CMD     equ 0xA0
PIC2_DATA    equ 0xA1
PIC_EOI      equ 0x20

%macro SET_GATE 2
    ; %1 = vector, %2 = handler
    mov eax, %2
    mov ebx, %1
    lea edx, [idt + ebx*8]
    ; offset low
    mov word [edx], ax
    ; selector
    mov word [edx + 2], CODE_SEL
    ; zero
    mov byte [edx + 4], 0
    ; type attributes: present=1, DPL=0, type=0xE (32-bit interrupt gate)
    mov byte [edx + 5], 0x8E
    ; offset high
    shr eax, 16
    mov word [edx + 6], ax
%endmacro

extern irq_timer
extern irq_keyboard

section .text
global idt_init
global isr_timer
global isr_keyboard

idt_init:
    push ebp
    mov ebp, esp

    ; Remap PIC: master->0x20, slave->0x28
    mov al, 0x11
    out PIC1_CMD, al
    out PIC2_CMD, al
    mov al, 0x20
    out PIC1_DATA, al
    mov al, 0x28
    out PIC2_DATA, al
    mov al, 0x04
    out PIC1_DATA, al
    mov al, 0x02
    out PIC2_DATA, al
    mov al, 0x01
    out PIC1_DATA, al
    mov al, 0x01
    out PIC2_DATA, al
    ; Unmask only IRQ0 (timer) and MASK IRQ1 (keyboard)
    ; Bit=0 -> unmask, Bit=1 -> mask. IRQ0(bit0)=0, IRQ1(bit1)=1, others=1
    mov al, 0xFE ; 11111110b
    out PIC1_DATA, al
    mov al, 0xFF
    out PIC2_DATA, al

    ; Set IDT gates for IRQ0/IRQ1
    SET_GATE 32, isr_timer
    SET_GATE 33, isr_keyboard

    ; Load IDT
    lidt [idtr]
    sti

    pop ebp
    ret

isr_timer:
    push ebp
    mov ebp, esp
    pushad
    call irq_timer
    popad
    mov al, PIC_EOI
    out PIC1_CMD, al
    pop ebp
    iret

isr_keyboard:
    push ebp
    mov ebp, esp
    pushad
    call irq_keyboard
    popad
    mov al, PIC_EOI
    out PIC1_CMD, al
    pop ebp
    iret